package thread.cyclic.barrier;

import thread.Worker;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;

/**
 * 主要是CyclicBarrier的使用
 * 对于cyclicBarrier而言，它起的作用其实也是类似于CountDownLatch那样
 * 不同:
 * 1.它可以重置count，达到复用的效果；
 * 2.只感觉有个线程拦截作用【相当于线程屏障，让子线程都等待一下，直到拦截的子线程数达到barrier设置的数量，然后接着执行各自的任务】
 * 3.cyclicBarrier并不会说给主线程执行任务的资源【即无法达到子线程数为barrier数的时候让主线程去执行某一件事】；
 * 4.子线程数超过设置的屏障数后不会感觉到任何效果；
 * 5.适用于需要等待数量达到屏障数线程数，然后才能去执行其他任务的场景；
 *
 * @author wei.yang on 2018/8/7
 */
@SuppressWarnings(value = {"Duplicates", "unused"})
public class CyclicBarrierQueue {

    private static final int DEFAULT_CYCLIC_TIMES1 = 2;

    private static final int DEFAULT_CYCLIC_TIMES2 = 3;

    private static final int DEFAULT_CYCLIC_TIMES3 = 8;

    private static final int DEFAULT_CYCLIC_COUNT = 3;

    public static void main(String[] args) {
        // barrierType1();
        barrierType2();
        // barrierType3();
        // barrierType4();
    }

    /**
     * 场景一
     * 子线程数没有屏障数大【子线程后续任务会一直被中断】
     */
    private static void barrierType1() {
        ExecutorService worker = Worker.getWorker();
        /*
            CyclicBarrier 中的index为0的时候执行barrierAction【index初始值即屏障数】
         */
        final CyclicBarrier barrier = new CyclicBarrier(DEFAULT_CYCLIC_COUNT, () -> System.out.println("barrier"));
        for (int i = 0; i < DEFAULT_CYCLIC_TIMES1; i++) {
            worker.execute(() -> {
                try {
                    System.out.println("start:\t" + Thread.currentThread().getName() + "\t" + System.currentTimeMillis());
                    barrier.await();
                    Thread.sleep(2000);
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("end  :\t" + Thread.currentThread().getName() + "\t" + System.currentTimeMillis());
                }
            });
        }
        try {
            Thread.sleep(0);
            System.out.println("main thread print log");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 场景二
     * 子线程数比屏障数大【当任务量大于屏障数的情况下，cyclicBarrier会每拦截【屏障数】线程然后执行cyclicCommand，
     * 然后更新屏障【类似重置】】
     * dowait(boolean timed, long nanos)
     * index=count---> index-- --> index==0的时候执行barrierCommand，然后执行nextGeneration();更新屏障信息
     *
     * @code nextGeneration() ---> Updates state on barrier trip and wakes up everyone.
     * trip.signalAll();-----> count = parties;--->generation = new Generation();
     * 做了三件事：唤醒上一个屏障拦截线程，更新count值用于初始化屏障【相当于】，开始下一个拦截;
     * 由于线程池在运行时会根据当前存活的线程、队列长度来判断是非创建新线程，故这里如果队列很大的话会导致一直无新线程创建；
     */
    private static void barrierType2() {
        ExecutorService worker = Worker.getWorker();
        final CyclicBarrier barrier = new CyclicBarrier(DEFAULT_CYCLIC_COUNT, () -> System.out.println("barrier"));
        for (int i = 0; i < DEFAULT_CYCLIC_TIMES3; i++) {
            worker.execute(() -> {
                try {
                    System.out.println("start:\t" + Thread.currentThread().getName() + "\t" + System.currentTimeMillis());
                    barrier.await();
                    Thread.sleep(20000);
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("end  :\t" + Thread.currentThread().getName() + "\t" + System.currentTimeMillis());
                }
            });
        }
        try {
            Thread.sleep(0);
            System.out.println("main thread print log");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 场景三
     * 子线程数和屏障数一样大
     */
    private static void barrierType3() {
        ExecutorService worker = Worker.getWorker();
        final CyclicBarrier barrier = new CyclicBarrier(DEFAULT_CYCLIC_COUNT);
        for (int i = 0; i < DEFAULT_CYCLIC_COUNT; i++) {
            worker.execute(() -> {
                try {
                    System.out.println("start:\t" + Thread.currentThread().getName() + "\t" + System.currentTimeMillis());
                    barrier.await();
                    Thread.sleep(2000);
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("end  :\t" + Thread.currentThread().getName() + "\t" + System.currentTimeMillis());
                }
            });
        }
        try {
            Thread.sleep(0);
            System.out.println("main thread print log");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 场景三
     * 子线程数和屏障数一样大,barrier设置Runnable
     */
    private static void barrierType4() {
        ExecutorService worker = Worker.getWorker();
        final CyclicBarrier barrier = new CyclicBarrier(DEFAULT_CYCLIC_COUNT, () -> System.out.println("barrier"));
        for (int i = 0; i < DEFAULT_CYCLIC_COUNT; i++) {
            worker.execute(() -> {
                try {
                    System.out.println("start:\t" + Thread.currentThread().getName() + "\t" + System.currentTimeMillis());
                    barrier.await();
                    Thread.sleep(20000);
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("end  :\t" + Thread.currentThread().getName() + "\t" + System.currentTimeMillis());
                }
            });
        }
        try {
            Thread.sleep(0);
            System.out.println("main thread print log");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
